import serial
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
from enum import Enum

'''
AI模拟量输入 Modbus地址：40051-40058，功能码：03，地址：50
DI数字量输入 Modbus地址：10001-10008，功能码：02，地址：0
DO继电器输出 Modbus地址：00001-00008，功能码：05，15，地址：0
1. 读AI模拟量输入：读取8路AI数据，模块地址=1.
主机发送：01 03 00 32 00 08 E5 C3        0032H - 对应模拟量输入通道0 <40051寄存器> 该寄存器地址位于【4】区
                                        0008H - 读取8个寄存器里的内容 <40051-40058寄存器> 
从机应答：01 03 10 11 A1 12 A2 13 A3 14 A4 15 A5 16 A6 17 A7 18 A8 1F 89    
                                        10H - 返回16个byte的数据，AI个数 * 2字节 = 8 * 2 = 16【十进制】
                                        11A1H - 0通道值：4513
                                        12A2H - 1通道值：4770


2. 读DI开关量输入：读取8路DI，模块地址=1.
主机发送：01 02 00 00 00 08 79 CC        0000H - 该寄存器对应DI0的开关状态 <10001寄存器> 该寄存器地址位于【1】区
                                        0008H - 读取8个开关量输入状态 <10001-10008寄存器>
从机应答：01 02 01 02 20 49              01H - 1个字节的开关量输入状态
                                        02H - 从低位到高位代表DI0-DI7的输入状态 02H即表示：DI-1高电平ON，其他低电平OFF

3. 写DO多路开关量输出：模块地址=1.
主机发送：01 0F 00 00 00 08 01 FF BE D5      0FH - 功能码，写多个线圈
                                            0000H - 线圈起始地址，开关量输出通道0的开关状态<00001寄存器>，该寄存器地址位于【0】区
                                            0008H - 线圈长度，8个输出开关量输出
                                            01H - 寄存器长度
                                            FFH - 线圈状态，从低位到高位代表DO0-DO7的开关状态
从机应答：01 0F 00 00 00 08 54 0D

4. 写DO单路开关量输出：模块地址=1.
主机发送《DO-0闭合》：01 05 00 00 FF 00 8C 3A 《Modbus RTU》      05H - 功能码，写单个线圈
                                                                0000H - 开关量输出通道0的开关状态<00001寄存器>;
主机发送《DO-0闭合》：01 05 00 07 FF 00 8C 3A 《Modbus RTU》      0007H - 开关量输出通道7的开关状态<00008寄存器>,该寄存器地址位于【0】区
                                                                FF00H -将FF00H写入0000H寄存器中,FF00H：表示DO闭合 0000H：表示DO断开
从机应答《DO-0闭合》：01 05 00 00 FF 00 8C 3A 《Modbus RTU》                                    
'''
'''0x03功能：读取AI模拟量输入'''
class AI_Address_single(Enum):
    (
        AI0, AI1, AI2, AI3, AI4, AI5, AI6, AI7)=(
        0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039
    )
ai_address = 0x0032
'''0x02功能'''
class DI_Address_single(Enum):
    (
        X0, X1, X2, X3, X4, X5, X6, X7) = (
        0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007
    )
di_address = 0x0000
'''0x05/0x0F功能'''
class DO_Address_single(Enum):
    (
        Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7) = (
        0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007
    )
do_Address = 0x0000
'''Y State'''
Y_on = 0xFF00
Y_off = 0x0000
All_Y_on = [1,1,1,1,1,1,1,1]
All_Y_off = [0,0,0,0,0,0,0,0]

class Modbus():
    def __init__(self,PORT):
        if serial.Serial.isOpen:
            serial.Serial.close
        self.master = modbus_rtu.RtuMaster(serial.Serial(PORT,baudrate=9600,parity='N',stopbits=1,xonxoff=0))
        self.master.set_timeout(1.0)

    def read_coils(self,start_address,numb):
        res= self.master.execute(1,cst.READ_COILS,start_address,numb)
        return res

    def read_discrete_inputs(self,start_address,numb):
        res= self.master.execute(1,cst.READ_DISCRETE_INPUTS,start_address,numb)
        return res

    def read_holding_registers(self,start_address,numb):
        res= self.master.execute(1,cst.READ_HOLDING_REGISTERS,start_address,numb)
        return res

    def read_input_registers(self,start_address,numb):
        res= self.master.execute(1,cst.READ_INPUT_REGISTERS,start_address,numb)
        return res

    def write_single_coil(self,start_address,data):
        res = self.master.execute(1,cst.WRITE_SINGLE_COIL,start_address,output_value=data)
        return res

    def write_single_register(self,start_address,data):
        res = self.master.execute(1,cst.WRITE_SINGLE_REGISTER,start_address,output_value=data)
        return res

    def write_multiple_coils(self,start_address,data=[1,1,0,0,1]):
        res = self.master.execute(1,cst.WRITE_MULTIPLE_COILS,start_address,output_value=data)
        return res

    def write_multiple_registers(self,start_address,data=[0x11,0x12]):
        print('cst.WRITE_MULTIPLE_REGISTERS is： {}'.format(cst.WRITE_MULTIPLE_REGISTERS))
        res = self.master.execute(1,cst.WRITE_MULTIPLE_REGISTERS,start_address,output_value=data)
        return res

    


if __name__ == '__main__':
    '''初始化串口'''
    comm = Modbus('COM8')

    # '''0x03:读取8路AI数据'''
    # all_ai_data = comm.read_holding_registers(ai_address,0x0008)
    # print('all_ai_data is: {}'.format(all_ai_data))

    # '''0x03:读取单路AI数据'''
    # ai_data = comm.read_holding_registers(AI_Address_single.AI0.value,0x0001)
    # print('single_ai_data is: {}'.format(ai_data))

    # '''0x02:读取8路DI数据'''
    # all_di_data = comm.read_discrete_inputs(di_address,0x0008)
    # print('all_di_data is: {}'.format(all_di_data))

    # '''0x02:读取单路DI数据'''
    # di_data = comm.read_discrete_inputs(DI_Address_single.X0.value,0x0001)
    # print('Single_di_data is: {}'.format(di_data))

    # '''0x0F:多路开关量输出'''
    # do_data = comm.write_multiple_coils(do_Address,All_Y_on)
    # print('All_do_data is: {}'.format(do_data))

    '''0x05:单路开关量输出'''
    comm.write_single_coil(DO_Address_single.Y1.value,Y_off)
    do_data = comm.write_single_coil(DO_Address_single.Y0.value,Y_off)
    print('Single_do_data is: {}'.format(do_data))